package protomysql

import (
	"encoding/binary"
	"fmt"
	"math"
)

const (
	MYSQL_TYPE_INT        = 3
	MYSQL_TYPE_LONG       = 8
	MYSQL_TYPE_VAR_STRING = 253
	MYSQL_TYPE_STRING     = 254
	MYSQL_TYPE_DOUBLE     = 5
	MYSQL_TYPE_TINY       = 1
)

type FieldType int

func GetFieldHandle(t int) IFieldHandle {
	fieldMap := map[int]IFieldHandle{
		MYSQL_TYPE_VAR_STRING: &FieldVarString{},
		MYSQL_TYPE_LONG:       &FieldLong{},
		MYSQL_TYPE_STRING:     &FieldString{},
		MYSQL_TYPE_INT:        &FieldInt{},
		MYSQL_TYPE_DOUBLE:     &FieldDouble{},
		MYSQL_TYPE_TINY:       &FieldTiny{},
	}
	if v, ok := fieldMap[t]; ok {
		return v
	}
	return nil
}

type IFieldHandle interface {
	ProcessBytes(mysqlStream *MysqlStream) string
}

type FieldString struct {
}

func (f *FieldString) ProcessBytes(mysqlStream *MysqlStream) string {
	return "'" + mysqlStream.ReadLengthEncodedString() + "'"
}

type FieldLong struct {
}

func (f *FieldLong) ProcessBytes(mysqlStream *MysqlStream) string {
	return fmt.Sprintf("%d", int(binary.LittleEndian.Uint64(mysqlStream.ReadBytes(8))))
}

type FieldVarString struct {
}

func (f *FieldVarString) ProcessBytes(mysqlStream *MysqlStream) string {
	return "'" + mysqlStream.ReadLengthEncodedString() + "'"
}

type FieldInt struct {
}

func (f *FieldInt) ProcessBytes(mysqlStream *MysqlStream) string {
	return fmt.Sprintf("%d", int(binary.LittleEndian.Uint32(mysqlStream.ReadBytes(4))))
}

type FieldDouble struct {
}

func (f *FieldDouble) ProcessBytes(mysqlStream *MysqlStream) string {
	val := math.Float64frombits(binary.LittleEndian.Uint64(mysqlStream.ReadBytes(8)))
	return fmt.Sprintf("%f", val)
}

type FieldTiny struct {
}

func (f *FieldTiny) ProcessBytes(mysqlStream *MysqlStream) string {
	res := make([]byte, 2)
	res[1] = mysqlStream.ReadBytes(1)[0]
	return fmt.Sprintf("%d", int(binary.LittleEndian.Uint16(res)))
}
